home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / MacStarter Pascal 1.0 / xWindows definition files / TextReader.p < prev    next >
Encoding:
Text File  |  1993-06-12  |  11.1 KB  |  370 lines  |  [TEXT/PJMM]

  1. unit TextReader;
  2.  
  3. interface
  4.  
  5. uses
  6.     xWindow, xTextWindow;
  7.  
  8. const
  9.     maxWordLength = 31;
  10.     endOfData = chr(255);
  11.     endOfLine = chr(13);
  12.     tab = chr(9);
  13.     space = ' ';
  14.     badReal = 1e2001;
  15.  
  16. type
  17.  
  18.     WordString = string[maxWordLength];
  19.  
  20.     Position = longint;
  21.  
  22.     TextReader = object
  23.  
  24.       { THE FOLLOWING VARIABLES can be changed to control the behavior of the }
  25.       { text reader. }
  26.  
  27.             whiteSpaceChars: set of char;  { set of chars that SkipWhiteSpace will skip over. }
  28.                   { Default value, after call to setup procedure, is [space,tab,endOfLine]. }
  29.             wordChars: set of char;  { set of chars that ReadWord will allow in a word }
  30.                   { Default value, after call to setup procedure, is ['a'..'z','A'..'Z']. }
  31.             discardExtraWordChars: boolean;  { if a word encountered by ReadWord is longer }
  32.                   { than MaxWordLength, this variable controls whether the extra chars are}
  33.                   { read and discarded or left there to be read later (by next ReadWord call, e.g. ) }
  34.             convertWordsToLowerCase: boolean; { if true, ReadWords converts uppercase letters }
  35.                   { in the word it reads to lower case }
  36.             commentStart: char;  { if the value of commentStart is NOT a space, then SkipWhiteSpace }
  37.                   { will skip over comments, as well as any chars in whiteSpaceChars.  The }
  38.                   { comment ends when the endOfData is reached or when the commentEnd char }
  39.                   { is encountered.  Default value is a space. }
  40.             commentEnd: char;  { Default value is endOfLine }
  41.  
  42.      { VARIABLES YOU CAN LOOK AT BUT NOT CHANGE }
  43.  
  44.             numError: boolean;   { After a call to ReadInteger or ReadReal, this is set to TRUE }
  45.                   { if a number has been successfully read, and to FALSE otherwise }
  46.             errorPosition: Position;   { whenever numError is set to TRUE, errorPosition }
  47.                   { to the current position in the text being read. }
  48.  
  49.       { VARIABLES YOU SHOULD'T MESS WITH }
  50.  
  51.             theTextWin: xTextWindow;
  52.             theText: CharsHandle;
  53.             theTextSize: integer;
  54.             thePos: Position;
  55.             fromString: boolean;
  56.  
  57.             procedure SetUp (chars: CharsHandle;
  58.                                         size: longint);
  59.          { Installs text to be read by the text reader; size tells how many chars there are, }
  60.          { and might be, for example, GetHandleSize(Handle(chars)).  Also sets the text}
  61.          { reader to begin reading at the beginning of the text, and assigns default values }
  62.          { to whiteSpaceChars, commentStart, etc. }
  63.             procedure SetupFromTextWindow (win: xTextWindow);
  64.          { Like SetUp, but uses the text from the xTextWindow.  (Text should not be edited }
  65.          { while reader is reading. If editing might have occured, call Reset.) }
  66.             procedure SetupFromString (str: string);
  67.          { Like SetUp, but instals a COPY of the string to be read by the read. }
  68.             procedure DisposeStringData;
  69.          { SetUpFromString allocates a CharsHandle to store the copy of the contents of }
  70.          { the string; after reading, call this to dispose of that CharsHandle.  If you just }
  71.          { call another SetUp proc, the handle will NOT be disposed, and the space it }
  72.          { occupies is lost. }
  73.             procedure reset;
  74.          { Start reading from beginning again. (Set reading position to 0, but also check }
  75.          { for changes in size of text, if text comes from an xTextWindow. }
  76.             procedure setPosition (pos: Position);
  77.          { sets reading position in text}
  78.             procedure skipWhiteSpace;
  79.          { reads and discards any chars in the set whiteSpaceChars; also read past comments }
  80.          { is commentStart is not a space. }
  81.             procedure readChar (var ch: char);
  82.          { reads and returns next char in text; if there are no more chars, endOfData is returned }
  83.             procedure readWord (var word: WordString);
  84.          { SKIPS TO NEXT CHAR in the set wordChars, then reads a sequence of chars in }
  85.          { wordChars and returns it in the parameter words.  If endOfData is encountered}
  86.          { while skipping junk, an empty string is returned.  A maximum of maxWordLength }
  87.          { chars will be returned in word; if more are found, result depends on value of }
  88.          { discardExtraWordChars .   If convertWords ToLowerCase is true, any uppercase }
  89.          { chars word are converted to lower case. }
  90.             procedure readInteger (var n: longint);
  91.          { calls SkipWhiteSpace, then tries to read an integer.  If a legal integer is read, it }
  92.          { is returned and numError is set to FALSE.  If not, then numError is set to TRUE, }
  93.          { errorPosition is set to the position in the text where error was found, and a }
  94.          { value of + or - maxlongint will be returned.  Note:  If number starts with a }
  95.          { + or - sign, spaces and tabs between the sign and the first digit will be allowed.) }
  96.             procedure readReal (var x: extended);
  97.          { Just like readInteger, but reads a real number.  Exponents allowed, but not }
  98.          { more than three digits are allowed in the exponent.  If an error occurs, the }
  99.          { value returned will be badReal. }
  100.             function GetChar: char;
  101.          { ReadChar as a function }
  102.             function moreChars: boolean;
  103.          { tests if there are any more chars in the text still to be read. }
  104.             function next: char;
  105.          { returns next char without reading it (i.e. tells you what the next char }
  106.          { returned by readChar or GetChar would be);  can return endOfData. }
  107.             function where: Position;
  108.          { returns current position in text }
  109.         end;
  110.  
  111. implementation
  112.  
  113. procedure TextReader.Setup (chars: charsHandle;
  114.                                 size: longint);
  115.     begin
  116.         theText := chars;
  117.         theTextSize := size;
  118.         theTextWin := nil;
  119.         thePos := 0;
  120.         commentStart := ' ';
  121.         commentEnd := endOfLine;
  122.         whiteSpaceChars := [space, tab, endOfLine];
  123.         wordChars := ['a'..'z', 'A'..'Z'];
  124.         discardExtraWordChars := true;
  125.         convertWordsToLowerCase := false;
  126.         fromString := false;
  127.         numError := false;
  128.     end;
  129.  
  130. procedure TextReader.SetupFromTextWindow (win: xTextWindow);
  131.     begin
  132.         Setup(nil, 0);
  133.         theText := CharsHandle(win.TE^^.hText);
  134.         theTextSize := win.TE^^.teLength;
  135.         theTextWin := win;
  136.     end;
  137.  
  138. procedure TextReader.SetUpFromString (str: string);
  139.     var
  140.         i: integer;
  141.     begin
  142.         Setup(nil, 0);
  143.         theText := CharsHandle(NewHandle(length(str)));
  144.         theTextSize := length(str);
  145.         for i := 1 to length(str) do
  146.             theText^^[i - 1] := str[i];
  147.         fromString := true;
  148.     end;
  149.  
  150. procedure TextReader.DisposeStringData;
  151.     begin
  152.         if fromString then begin
  153.                 DisposHandle(Handle(theText));
  154.                 theText := nil;
  155.                 theTextSize := 0;
  156.                 thePos := 0;
  157.                 fromString := false;
  158.             end;
  159.     end;
  160.  
  161. procedure TextReader.reset;
  162.     begin
  163.         if theTextWin <> nil then
  164.             theTextSize := theTextWin.TE^^.teLength;
  165.         thePos := 0;
  166.     end;
  167.  
  168. procedure TextReader.setPosition (pos: Position);
  169.     begin
  170.         thePos := pos;
  171.         if pos < 0 then
  172.             Pos := 0
  173.         else if pos > theTextSize then
  174.             pos := theTextSize;
  175.     end;
  176.  
  177. procedure TextReader.skipWhiteSpace;
  178.     begin
  179.         while (thePos < theTextSize) & ((theText^^[thePos] in whiteSpaceChars) | (theText^^[thePos] = commentStart)) do
  180.             if (commentStart <> space) & (theText^^[thePos] = commentStart) then begin
  181.                     repeat
  182.                         thePos := thePos + 1
  183.                     until (thePos = theTextSize) | (theText^^[thePos] = commentEnd);
  184.                     if thePos < theTextSize then
  185.                         thePos := thePos + 1;
  186.                 end
  187.             else
  188.                 thePos := thePos + 1;
  189.     end;
  190.  
  191. procedure TextReader.readChar (var ch: char);
  192.     begin
  193.         if thePos >= theTextSize then
  194.             ch := endOfData
  195.         else begin
  196.                 ch := theText^^[thePos];
  197.                 thePos := thePos + 1;
  198.             end;
  199.     end;
  200.  
  201. procedure TextReader.readWord (var word: WordString);
  202.     var
  203.         ch: char;
  204.         i: integer;
  205.     begin
  206.         while not (next in wordChars) do
  207.             thePos := thePos + 1;
  208.         if thePos >= theTextSize then
  209.             word := ''
  210.         else begin
  211.                 word := '';
  212.                 ch := next;
  213.                 while (ch in wordChars) & (length(word) < maxWordLength) do begin
  214.                         ReadChar(ch);
  215.                         word := Concat(word, ch);
  216.                         ch := next;
  217.                     end;
  218.                 if discardExtraWordChars then
  219.                     while ch in wordChars do begin
  220.                             readChar(ch);
  221.                             ch := next;
  222.                         end;
  223.                 if convertWordsToLowerCase then begin
  224.                         for i := 1 to length(word) do
  225.                             if word[i] in ['A'..'Z'] then
  226.                                 word[i] := chr(ord(word[i]) - ord('A') + ord('a'));
  227.                     end;
  228.             end;
  229.     end;
  230.  
  231. procedure TextReader.readInteger (var n: longint);
  232.     var
  233.         neg: boolean;
  234.         ch: char;
  235.         digit: longint;
  236.     begin
  237.         SkipWhiteSpace;
  238.         numError := false;
  239.         neg := next = '-';
  240.         if (next = '-') | (next = '+') then begin
  241.                 thePos := thePos + 1;
  242.                 while (thePos < theTextSize) & ((theText^^[thePos] = space) | (theText^^[thePos] = tab)) do
  243.                     thePos := thePos + 1;
  244.             end;
  245.         if not (next in ['0'..'9']) then begin
  246.                 numError := true;
  247.                 errorPosition := thePos;
  248.                 n := maxlongint;
  249.             end
  250.         else begin
  251.                 n := 0;
  252.                 ch := next;
  253.                 while ch in ['0'..'9'] do begin
  254.                         ch := GetChar;
  255.                         digit := ord(ch) - ord('0');
  256.                         if n > (maxlongint - digit) div 10 then begin
  257.                                 n := maxlongint;
  258.                                 numError := true;
  259.                                 errorPosition := thePos;
  260.                                 leave;
  261.                             end
  262.                         else
  263.                             n := 10 * n + digit;
  264.                         ch := next;
  265.                     end;
  266.             end;
  267.         if neg then
  268.             n := -n;
  269.     end;
  270.  
  271. procedure TextReader.readReal (var x: extended);
  272.     var
  273.         s: string;
  274.         ch: char;
  275.         ct: integer;
  276.         neg: boolean;
  277.     begin
  278.         SkipWhiteSpace;
  279.         numError := false;
  280.         neg := next = '-';
  281.         if (next = '-') | (next = '+') then begin
  282.                 thePos := thePos + 1;
  283.                 while (thePos < theTextSize) & ((theText^^[thePos] = space) | (theText^^[thePos] = tab)) do
  284.                     thePos := thePos + 1;
  285.             end;
  286.         if not (next in ['0'..'9', '.']) then begin
  287.                 numError := true;
  288.                 errorPosition := thePos;
  289.                 x := badReal;
  290.                 EXIT(readReal);
  291.             end;
  292.         s := '';
  293.         ct := 0;
  294.         while (next in ['0'..'9']) & (length(s) < 255) do
  295.             s := Concat(s, GetChar);
  296.         if (next = '.') & (length(s) < 255) then begin
  297.                 s := Concat(s, GetChar);
  298.                 while (next in ['0'..'9']) & (length(s) < 255) do
  299.                     s := Concat(s, GetChar);
  300.             end;
  301.         if (next in ['e', 'E']) & (length(s) < 255) then begin
  302.                 if s = '.' then begin
  303.                         numError := true;
  304.                         errorPosition := thePos;
  305.                         x := badReal;
  306.                         EXIT(readReal);
  307.                     end;
  308.                 s := Concat(s, GetChar);
  309.                 if (next in ['+', '-']) & (length(s) < 255) then
  310.                     s := Concat(s, GetChar);
  311.                 if not (next in ['0'..'9']) then begin
  312.                         numError := true;
  313.                         errorPosition := thePos;
  314.                         x := badReal;
  315.                         EXIT(readReal);
  316.                     end;
  317.                 while (next in ['0'..'9']) & (length(s) < 255) do begin
  318.                         s := Concat(s, GetChar);
  319.                         ct := ct + 1;
  320.                         if ct > 3 then begin
  321.                                 numError := true;
  322.                                 errorPosition := thePos;
  323.                                 x := badReal;
  324.                                 EXIT(readReal);
  325.                             end;
  326.                     end;
  327.             end;
  328.         IOCheck(false);
  329.         ReadString(s, x);
  330.         IOCheck(true);
  331.         if IOResult <> noErr then begin
  332.                 numError := true;
  333.                 errorPosition := thePos;
  334.                 x := badReal;
  335.                 EXIT(readReal);
  336.             end;
  337.         if neg then
  338.             x := -x;
  339.     end;
  340.  
  341. function TextReader.GetChar: char;
  342.     begin
  343.         if thePos >= theTextSize then
  344.             GetChar := endOfData
  345.         else begin
  346.                 GetChar := theText^^[thePos];
  347.                 thePos := thePos + 1;
  348.             end;
  349.     end;
  350.  
  351. function TextReader.moreChars: boolean;
  352.     begin
  353.         moreChars := thePos < theTextSize;
  354.     end;
  355.  
  356. function TextReader.next: char;
  357.     begin
  358.         if thePos >= theTextSize then
  359.             next := endOfData
  360.         else
  361.             next := theText^^[thePos];
  362.     end;
  363.  
  364. function TextReader.where: Position;
  365.     begin
  366.         where := thePos;
  367.     end;
  368.  
  369.  
  370. end.